#include <iostream>
#include <cstring>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "Log.hpp"

// const uint16_t pt = 80;
enum
{
    SOCKERR = -1,
    BINDERR,
    LISTENERR,
    ACCEPTERR,
    CONNECTERR
};

//单例模式 懒汉模式
class TcpServer
{
private:
    uint16_t port;
    int _listen_sockfd;
    static TcpServer *Sver;

private:
    TcpServer(const uint16_t _port) : port(_port), _listen_sockfd(-1)
    {
    }
    TcpServer(const TcpServer &Sver) = delete;
    TcpServer &operator=(const TcpServer &Sver) = delete;

public:
    TcpServer *GetInstance()
    {
        static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
        if (Sver == nullptr)
        {
            pthread_mutex_lock(&lock);
            if (Sver == nullptr)
            {
                Sver = new TcpServer(80);
                Sver->initServer();
            }
            pthread_mutex_unlock(&lock);
        }
    }

    void initServer()
    {
        Socket();
        Bind();
        Listen();
    }

    void Socket()
    {
        _listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listen_sockfd < 0)
        {
            lg(FATAL, "socket success... sockfd: %d, errno: %d, strerror: %s", _listen_sockfd, errno, strerror(errno));
            exit(SOCKERR);
        }

        // 端口和地址复用
        int opt = 1;
        setsockopt(_listen_sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
    }
    void Bind()
    {
        struct sockaddr_in Server;
        Server.sin_family = AF_INET;
        Server.sin_addr.s_addr = INADDR_ANY; // #define	INADDR_ANY		((in_addr_t) 0x00000000)
        Server.sin_port = htons(port);
        socklen_t len = sizeof(Server);
        int n = bind(_listen_sockfd, (struct sockaddr *)&Server, len);
        // std::cout << _sockfd << std::endl;
        if (n < 0)
        {
            lg(FATAL, "bind fail... sockfd: %d, errno: %d, strerror: %s", _listen_sockfd, errno, strerror(errno));
            exit(BINDERR);
        }
    }

    void Listen()
    {
        int n = listen(_listen_sockfd, 5);
        if (n < 0)
        {
            lg(FATAL, "listen fail... sockfd: %d, errno: %d, strerror: %s", _listen_sockfd, errno, strerror(errno));
            exit(LISTENERR);
        }
    }
};

TcpServer *TcpServer::Sver = nullptr;